﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using G.Model;

namespace GameControls
{
    public abstract class GameDisplayer : IDisposable
    {
        public static readonly Color DEFAULT_BACK_COLOR = Color.WhiteSmoke;
        
        private readonly Dictionary<GameLocation, BoardShape> _Shapes = 
            new Dictionary<GameLocation, BoardShape>();
        private readonly List<BoardShapeDisplayer> _Displayers = 
            new List<BoardShapeDisplayer>();
        private readonly GameSpaceDef _GameDef;
        private readonly BoardShapeContainer _Container;
        private readonly ActiveObject _ActiveObject;
        private Color _SquareColor = Color.WhiteSmoke;
        
        private int _SquareSize;

        public GameDisplayer(GameSpaceDef game, 
                             BoardShapeContainer container, 
                             int pSquareSize)
        {
            _GameDef = game;
            _Container = container;
            _SquareSize = pSquareSize;
            _ActiveObject = new ActiveObject();
            game.GameElementDefs.ElementRemovedEvent += 
                this.OnElementRemoved;
        }
        
        public virtual void Dispose()
        {
            foreach (BoardShapeDisplayer displayer in _Displayers) 
            {
                displayer.Dispose();
            }
            _GameDef.GameElementDefs.ElementRemovedEvent -= this.OnElementRemoved;
        }

        protected virtual void Init()
        {
            for (int x = 0; x < _GameDef.Width; x++)
            {
                for (int y = 0; y < _GameDef.Height; y++)
                {
                    BoardShape shape = CreateShape(new GameLocation(x, y));
                    BoardShapeDisplayer displayer = CreateDisplayer(shape);
                    displayer.DisplayIcon();
                }
            }
        }

        private BoardShape CreateShape(GameLocation loc)
        {
            BoardShape shape = new BoardShape(_Container, _SquareSize);
            shape.FillColor = Color.Black;
            shape.BackColor = DEFAULT_BACK_COLOR;

            shape.Size = new Size(_SquareSize, _SquareSize);
            shape.Location = ToPoint(loc);
            _Container.Add(shape);
            _Shapes.Add(loc, shape);

            return shape;
        }

        private GameLocation ToGameLocation(Point point)
        {
            return new GameLocation(
                point.X / _SquareSize, 
                point.Y / _SquareSize);
        }

        private Point ToPoint(GameLocation point)
        {
            return new Point(
                point.X * _SquareSize, 
                point.Y * _SquareSize);
        }
        
        public void ClearShape(GameLocation loc)
        {
            BoardShape shape = _Shapes[loc];

            shape.BackgroundImage = null;
        }

        public List<BoardShapeDisplayer> Displayers
        {
            get { return _Displayers; }
        }

        [Browsable(false)]
        public Dictionary<GameLocation, BoardShape> Shapes
        {
            get { return _Shapes; }
        }
        
        public ActiveObject ActiveObject
        {
            get { return _ActiveObject; } 
        }

        public GameSpaceDef GameDef
        {
            get { return _GameDef; }
        }

        public BoardShapeContainer ShapeContainer 
        {
            get { return _Container; }
        }

        public Color SquareColor 
        {
            get { return _SquareColor; }
            set
            {
                _SquareColor = value;
                foreach (BoardShapeDisplayer displayer in _Displayers) 
                {
                    displayer.Shape.BackColor = value;
                    displayer.DisplayIcon();
                    displayer.Shape.Invalidate();
                }
            }
        }
        
        private void OnElementRemoved(GameElementDef subject)
        {
            foreach (BoardShapeDisplayer displayer in _Displayers)
            {
                if (displayer.Location == subject.Location)
                {
                    displayer.DisplayIcon();
                    break;
                }
            }
        }

        protected abstract BoardShapeDisplayer CreateDisplayer(BoardShape shape);
        
    }
}
